package cn.txm.user.service.impl;

import cn.hutool.http.HttpUtil;
import cn.txm.basic.constant.Constant;
import cn.txm.basic.service.impl.BaseServiceImpl;
import cn.txm.basic.util.*;
import cn.txm.org.domain.Employee;
import cn.txm.org.mapper.EmployeeMapper;
import cn.txm.user.domain.User;
import cn.txm.user.domain.UserAddress;
import cn.txm.user.domain.WxUser;
import cn.txm.user.domain.dto.AccessTokenDto;
import cn.txm.user.domain.dto.UserDto;
import cn.txm.user.domain.dto.UserinfoDto;
import cn.txm.user.mapper.UserMapper;
import cn.txm.user.mapper.WxUserMapper;
import cn.txm.user.service.IUserService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    private WxUserMapper wxUserMapper;

    /**
     * 验证手机号是否被注册
     *
     * @param phone
     * @param type  phone_reg表示手机验证码注册，phone_login表示手机验证码登录
     * @return
     */
    @Override
    public AjaxResult validatePhone(String type, String phone) {
        //通过手机号查询t_user表
        User user = userMapper.findByPhone(phone);
        if (Constant.PHONE_REG.equals(type)) {
            //手机验证码注册
            if (user != null) {
                //手机号被注册过
                return AjaxResult.me().setSuccess(false).setMessage("该手机号已被占用");
            }
        } else if (Constant.PHONE_LOGIN.equals(type)) {
            //手机验证码登录
            if (user == null) {
                //手机号被注册了
                return AjaxResult.me().setMessage("该手机号未被占用");
            }
        }
        return AjaxResult.me();
    }

    /**
     * 发送手机短信
     *
     * @param phone
     * @param type  phone_reg表示手机验证码注册，phone_login表示手机验证码登录
     * @return
     */
    @Override
    public AjaxResult sendMobileCode(String type, String phone) {

        //1.随机生成一个验证码
        String verifyCode = StrUtils.getRandomString(6);
        //2.先从Redis中获取一下
        String value = RedisUtils.INSTANCE.get(type + "-" + phone);
        System.out.println(value);
        //获取当前系统时间的毫秒值
        long currentTime = System.currentTimeMillis();
        //Redis中有存储的验证码和时间毫秒  格式：验证码-时间毫秒
        if (StringUtils.hasText(value)) {
            //验证码
            verifyCode = value.split("-")[0];
            //获取时间毫秒值
            long lastTime = Long.valueOf(value.split("-")[1]);
            //在一分钟以内的
            if (currentTime - lastTime <= 60 * 1000) {
                return AjaxResult.me().setSuccess(false).setMessage("亲！！请不要频繁操作");
            } else if (currentTime - lastTime <= 300 * 1000) {//当时间小于5分钟，刷新时间
                RedisUtils.INSTANCE.set(type + "-" + phone, verifyCode + "-" + currentTime);
                String content = "【宠物之家】亲你的验证码为：" + verifyCode + "，请在5分钟内完成操作！";

                //调用SMS网建设发送短信
                //SmsUtils.send(phone, content);
                System.out.println(content);
            }

        } else {//超过5分钟，或者就是第一次获取
            //保存到Redis中，并且设置5分钟过期  key: phone_reg-18996157300  value：验证码-时间毫秒
            RedisUtils.INSTANCE.set(type + "-" + phone, verifyCode + "-" + currentTime, 300);
            String content = "【宠物之家】亲你的验证码为：" + verifyCode + "，请在5分钟内完成操作！";

            //调用SMS网建设发送短信
            //SmsUtils.send(phone, content);
            System.out.println(content);
        }
        return AjaxResult.me().setMessage("短信验证码已发送，请在5分钟内完成操作！");
    }


    /**
     * 前台用户注册，提交注册表单
     * @param userDto
     * @return
     */
    @Override
    @Transactional
    public AjaxResult phoneReg(UserDto userDto) {
        //如果是手机注册
        //从Redis中获取一下

        /*System.out.println(1+"-----"+Constant.PHONE_REG.equals(userDto.getType()));*/

        if (Constant.PHONE_REG.equals(userDto.getType())) {

            /*System.out.println(2+"-----"+Constant.PHONE_REG.equals(userDto.getType()));*/

            String value = RedisUtils.INSTANCE.get(userDto.getType() + "-" + userDto.getPhone());
            //能够从redis中获取到验证码
            if (StringUtils.hasText(value)) {
                /*System.out.println(3+"-----"+StringUtils.hasText(value));*/

                //验证码
                String verifyCode = value.split("-")[0];
                if (verifyCode.equals(userDto.getVerifyCode())) {
                    /*System.out.println(4+"-----"+verifyCode.equals(userDto.getVerifyCode()));*/

                    //验证码正确，将数据保存到t_user表中save方法需要一个User对象，但是传递的是User的子类对象
                    userDto.setUsername(userDto.getPhone());

                    /*System.out.println("phone----"+userDto.getPhone());*/
                    userDto.setSalt(StrUtils.getComplexRandomString(32));

                    /*System.out.println("userDto保存前----"+userDto);*/
                    //密码加密后保存
                    userDto.setPassword(MD5Utils.encrypByMd5(userDto.getPassword() + userDto.getSalt()));
                    userMapper.save(userDto);

                    /*System.out.println("userDto保存后----"+userDto);*/

                    return AjaxResult.me();
                }
            }
            return AjaxResult.me().setSuccess(false).setMessage("验证码错误");
        } else if (Constant.EMAIL_REG.equals(userDto.getType())) {
            //邮箱注册
            //....自己完成
        }
        return AjaxResult.me().setSuccess(false).setMessage("注册失败，我们正在殴打程序员......");
    }

    /**
     * 用户登录
     * @param userDto  type属性为front表示前台用户登录，admin表示后台用户登录
     * @return
     */
    @Override
    public AjaxResult userLogin(UserDto userDto) {
        //前台用户登录：查询t_user
        if (Constant.FRONT.equals(userDto.getType())) {
            User loginUser = userMapper.findByAccount(userDto.getUsername());
            if (loginUser != null) {
                //先将前端传递的密码通过md5加密后，再与数据库中查询到的密码进行比较
                String md5Password = MD5Utils.encrypByMd5(userDto.getPassword() + loginUser.getSalt());
                //如果加密后的密码与库里的密码相同
                if (md5Password.equals(loginUser.getPassword())) {
                    return loginSuccess(loginUser);
                }
                return AjaxResult.me().setSuccess(false).setMessage("密码错误");
            }
            return AjaxResult.me().setSuccess(false).setMessage("用户不存在");
        }//后台用户登录：查询t_employee
        else if (Constant.ADMIN.equals(userDto.getType())) {
            Employee employee = employeeMapper.findByusername(userDto.getUsername());
            if (employee != null) {
                String code = userDto.getPassword() + employee.getSalt();
                if (code.equals(employee.getPassword())){
                    //登录成功后，利用UUID生成一个token
                    String userToken = UUID.randomUUID().toString();
                    employee.setPassword(null);
                    //Redis中存储对象，需要先将对象转化为json字符串
                    String loginUserJsonStr = JsonUtils.toJsonString(employee);
                    //存储到Redis中
                    RedisUtils.INSTANCE.set(userToken, loginUserJsonStr, Constant.EXPIRE_TIME_IN_REDIS);
                    //将token和用户信息一起返回给前端，一般采用Map集合
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("userToken", userToken);
                    map.put("loginUser", loginUserJsonStr);

                    return AjaxResult.me().setData(map);
                }
            }
            return AjaxResult.me().setSuccess(false).setMessage("用户不存在");
        }
        return null;
    }

    /**
     * 手机验证码登录
     * @param userDto
     * @return
     */
    @Override
    public AjaxResult phoneLogin(UserDto userDto) {
        //根据账号查询数据库信息
        User loginUser = userMapper.findByAccount(userDto.getUsername());
        //如果查得到，就证明可以登录
        if (loginUser != null) {
            if (userDto.getUsername() != null) {
                String code = RedisUtils.INSTANCE.get(userDto.getType() + "-" + userDto.getUsername());
                System.out.println(code);
                String verifyCode = code.split("-")[0];
                if (userDto.getVerifyCode().equals(verifyCode)) {
                    //登录成功后，利用UUID生成一个token
                    String userToken = UUID.randomUUID().toString();
                    loginUser.setPassword(null);
                    //Redis中存储对象，需要先将对象转化为json字符串
                    String loginUserJsonStr = JsonUtils.toJsonString(loginUser);
                    //存储到Redis中
                    RedisUtils.INSTANCE.set(userToken, loginUserJsonStr, Constant.EXPIRE_TIME_IN_REDIS);
                    //将token和用户信息一起返回给前端，一般采用Map集合
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("userToken", userToken);
                    map.put("loginUser", loginUserJsonStr);

                    return AjaxResult.me().setData(map);
                }
                return AjaxResult.me().setSuccess(false).setMessage("验证码错误");
            }
        }
        return AjaxResult.me().setSuccess(false).setMessage("用户不存在");
    }


    /**
     * 微信登录接口：获取code参数，利用Java程序发送Http请求获取access_token
     * @param code
     * @return
     */
    @Override
    public AjaxResult wechatLogin(String code) {
        //1.发送请求，传递code作为参数，获取access_token
        String accessTokenUrl =Constant.ACCESS_TOKEN_URL
                .replace("APPID",Constant.APPID)
                .replace("SECRET", Constant.APPSECRET)
                .replace("CODE",code);
        //2.利用糊涂工具包发送请求
        String result = HttpUtil.get(accessTokenUrl);
        if(!StringUtils.hasText(result)){
            return AjaxResult.me().setSuccess(false).setMessage("微信登录失败！");
        }
        //3.将json字符串转为实体类对象
        AccessTokenDto accessTokenDto = JsonUtils.toObject(result, AccessTokenDto.class);
        System.out.println(accessTokenDto);
        //4.如果请求响应正常，就通过openid和unionid去查询t_wxuser表
        if(accessTokenDto.getErrcode()==null && !StringUtils.hasText(accessTokenDto.getErrmsg())){
            //通过openid和unionid去查询t_wxuser表
            WxUser wxUser = wxUserMapper.findByOpenidAndUnionid(accessTokenDto.getOpenid(), accessTokenDto.getUnionid());
            //5.登陆成功
            if (wxUser!=null){
                User loginUser = wxUser.getUser();
                return loginSuccess(loginUser);
            }
            //6.查询不到WxUser数据，表示之前未绑定过，前端应该跳转到绑定页面去
            return AjaxResult.me().setSuccess(false).setMessage("unbind").setData(accessTokenDto);
        }
        return AjaxResult.me().setSuccess(false).setMessage(" 微信登录失败 "+accessTokenDto.getErrcode()+"---"+accessTokenDto.getErrmsg());
    }


    /**
     * 微信用户绑定：通过账户密码绑定
     * @return
     */
    @Override
    @Transactional
    public AjaxResult userBindAccount(UserDto userDto) {
        //如果是账号密码绑定
        if(userDto.getType().equals(Constant.BIND_ACCOUNT)){
            System.out.println("userDto=----"+userDto);
            //1.通过access_token和openid获取用户个人信息,返回json字符串
            String userinfoUrl =Constant.WECHAT_USERINFO_URL
                    .replace("ACCESS_TOKEN",userDto.getAccess_token())
                    .replace("OPENID",userDto.getOpenid());
            String userinfoStr = HttpUtil.get(userinfoUrl);
            System.out.println("userinfoStr---"+userinfoStr);
            if (!StringUtils.hasText(userinfoStr)){
                return AjaxResult.me().setSuccess(false).setMessage("用户绑定失败！我们正在殴打程序员....");
            }
            //2.将json字符串转化为实体类对象
            UserinfoDto userinfoDto = JsonUtils.toObject(userinfoStr, UserinfoDto.class);
            System.out.println("userinfoDto-----"+userinfoDto);
            //3.保存数据到t_user表，返回主键
            userDto.setSalt(StrUtils.getComplexRandomString(32));
            userDto.setPassword(MD5Utils.encrypByMd5(userDto.getPassword()+userDto.getSalt()));
            userDto.setHeadImg(userinfoDto.getHeadimgurl());
            userMapper.save(userDto);
            //4.保存数据到t_wxuser表
            WxUser wxUser = new WxUser();
            wxUser.setOpenid(userinfoDto.getOpenid());
            wxUser.setNickname(userinfoDto.getNickname());
            wxUser.setSex(userinfoDto.getSex());
            wxUser.setAddress(userinfoDto.getCountry()+ " " + userinfoDto.getProvince()+ " " + userinfoDto.getCity());
            wxUser.setHeadimgurl(userinfoDto.getHeadimgurl());
            wxUser.setUnionid(userinfoDto.getUnionid());
            wxUser.setUser_id(userDto.getId());
            System.out.println("wxUser---"+wxUser);
            wxUserMapper.save(wxUser);
            //5.登录成功那儿的代码
            return loginSuccess(userDto);

        }else if(userDto.getType().equals(Constant.BIND_PHONE)){
            //手机验证码绑定
            System.out.println("userDto=----"+userDto);
            String code = RedisUtils.INSTANCE.get(userDto.getType() + "-" + userDto.getUsername());

            if(userDto.getVerifyCode().equals(code)){
                return AjaxResult.me().setSuccess(false).setMessage("验证码错误");
            }
            //1.通过access_token和openid获取用户个人信息,返回json字符串
            String userinfoUrl =Constant.WECHAT_USERINFO_URL
                    .replace("ACCESS_TOKEN",userDto.getAccess_token())
                    .replace("OPENID",userDto.getOpenid());
            String userinfoStr = HttpUtil.get(userinfoUrl);
            System.out.println("userinfoStr---"+userinfoStr);
            if (!StringUtils.hasText(userinfoStr)){
                return AjaxResult.me().setSuccess(false).setMessage("用户绑定失败！我们正在殴打程序员....");
            }
            //2.将json字符串转化为实体类对象
            UserinfoDto userinfoDto = JsonUtils.toObject(userinfoStr, UserinfoDto.class);
            System.out.println("userinfoDto-----"+userinfoDto);
            //3.保存数据到t_user表，返回主键
            userDto.setSalt(StrUtils.getComplexRandomString(32));
            userDto.setPassword(MD5Utils.encrypByMd5(userDto.getPassword()+userDto.getSalt()));
            userDto.setHeadImg(userinfoDto.getHeadimgurl());
            userMapper.save(userDto);
            //4.保存数据到t_wxuser表
            WxUser wxUser = new WxUser();
            wxUser.setOpenid(userinfoDto.getOpenid());
            wxUser.setNickname(userinfoDto.getNickname());
            wxUser.setSex(userinfoDto.getSex());
            wxUser.setAddress(userinfoDto.getCountry()+ " " + userinfoDto.getProvince()+ " " + userinfoDto.getCity());
            wxUser.setHeadimgurl(userinfoDto.getHeadimgurl());
            wxUser.setUnionid(userinfoDto.getUnionid());
            wxUser.setUser_id(userDto.getId());
            System.out.println("wxUser---"+wxUser);
            wxUserMapper.save(wxUser);
            //5.登录成功那儿的代码
            return loginSuccess(userDto);
        }
        return AjaxResult.me().setSuccess(false).setMessage("用户绑定失败！我们正在殴打程序员....");
    }

    /**
     * 前台：根据用户id查询用户地址
     * @param user_id
     * @return
     */
    @Override
    public List<UserAddress> loadUserAddress(Long user_id) {
        return userMapper.loadUserAddress(user_id);
    }

    /**
     * 登录成功后的处理
     * @param loginUser
     * @return
     */
    private AjaxResult loginSuccess(User loginUser) {
        //登录成功后，利用UUID生成一个token
        String userToken = UUID.randomUUID().toString();
        loginUser.setPassword(null);
        //Redis中存储对象，需要先将对象转化为json字符串
        String loginUserJsonStr = JsonUtils.toJsonString(loginUser);
        //存储到Redis中
        RedisUtils.INSTANCE.set(userToken, loginUserJsonStr, Constant.EXPIRE_TIME_IN_REDIS);

        //将token和用户信息一起返回给前端，一般采用Map集合
        Map<String,Object> map = new HashMap<>();
        map.put("userToken", userToken);
        map.put("loginUser", loginUserJsonStr);
        return AjaxResult.me().setData(map);
    }
}
